package handlers

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"math"
	"net/http"
	"strconv"
	"strings"
	"werewolf/core"
)

func OperationHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
		return
	}

	r.ParseForm()
	post := r.Form
	role := post.Get("b-info")
	self := post.Get("b-self")
	room := post.Get("b-room")
	preRole := post.Get("b-prev")

	handle, err := core.Connection()
	if err != nil {
		http.Error(w, "Connection failed: "+err.Error(), http.StatusInternalServerError)
		return
	}
	defer handle.Close()

	switch role {
	case "w":        //    狼人操作
		for key := range post {
			if key == "board" {
				id := post.Get(key)[6:]        //  袭击对象
				if !checkDevil(id, room){
					updateString := fmt.Sprintf("UPDATE Running SET death1=%s, w=%s, `%s`=-`%s` WHERE RmNo=%s", id, id, preRole, preRole, room)
					_, err := handle.Exec(updateString)
					if err != nil {
						http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
						return
					}
					fmt.Fprintln(w, "success")
					return
				}else{
					fmt.Fprintln(w, "devil")
				}
			}
		}

	case "g-witch":        //   女巫操作
		result1, result2, result3 := 0, 0, 0

		// 啥也不干
		queryString := fmt.Sprintf("UPDATE Running SET `g-witch`= ABS(`g-witch`)+ 4, `%s`=-`%s` WHERE RmNo=%s", preRole, preRole, room)
		_, err = handle.Exec(queryString)
		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}
		result3 = 1

		// 毒人
		if board := post.Get("board"); board != "" {
			id := board[6:]
			poisonedId := checkDevilKnight(id, room, self)
			_, err := handle.Exec("UPDATE Running SET `g-witch`= ABS(`g-witch`)+ 2, death2=? WHERE RmNo=?", poisonedId, room)
			if err == nil {
				result2 = 1
			}
		}

		// 救人
		if post.Get("flip-checkbox") == "on" {
			_, err := handle.Exec("UPDATE Running SET `g-witch`= ABS(`g-witch`)+ 1 WHERE RmNo=?", room)
			if err == nil {
				var guardId, killId int
				err = handle.QueryRow("SELECT `g-guard`, death1 FROM Running WHERE RmNo = ?", room).Scan(&guardId, &killId)
				if err != nil {
					http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
					return
				}
				if int(math.Abs(float64(guardId))) == int(math.Abs(float64(killId))) {
					_, err = handle.Exec("UPDATE Running SET death1 = 0,death2 = ? WHERE RmNo=?", killId, room)
					if err != nil {
						http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
						return
					}
				}else{
					_, err = handle.Exec("UPDATE Running SET death1 = 0 WHERE RmNo=?", room)
					if err != nil {
						http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
						return
					}
				}
				result1 = 1
			}
		}

		if result1 > 0 || result2 > 0 || result3 > 0 {
			http.Redirect(w, r, fmt.Sprintf("/room?room=%s&user=%s", room, self), http.StatusSeeOther)
		} else {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}

	case "g-seer":         //   预言家操作
		board := post.Get("board")

		poisonId := checkDevilKnight(board, room, self)
		if poisonId == board {
			poisonId = "0"
		}
		queryString := fmt.Sprintf("UPDATE Running SET `%s`=-`%s`, `g-seer`=%s, death3=%s WHERE RmNo=%s", preRole, preRole, board, poisonId, room)
		_, err = handle.Exec(queryString)
		if err == nil {
			fmt.Fprintln(w, "success")
		} else {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}

	case "g-guard":          //   守卫操作
		var last int
		err := handle.QueryRow("SELECT `g-guard` FROM Running WHERE RmNo=?", room).Scan(&last)
		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			return
		}
		var rowsAffected int64
		rowsAffected = 0
		var qResult sql.Result
		var id int


		if board := post.Get("board"); board != "" {
			id, _ = strconv.Atoi(board[6:])
			if int(math.Abs(float64(last))) == id {
				fmt.Fprint(w, "rechoose")
				return
			}	
		} else {
			id = 100
		}
		
		queryString := fmt.Sprintf("UPDATE Running SET `g-guard`= %d, `%s`=-`%s` WHERE RmNo = %s", id, preRole, preRole, room)
		qResult, _ = handle.Exec(queryString)
		rowsAffected, _ = qResult.RowsAffected()

		if rowsAffected > 0 {
			fmt.Fprint(w, "success")
		} else {
			http.Error(w, "error", http.StatusInternalServerError)
		}

	case "w-devil":  //   恶魔查验好人为平民还是为神职
		board := post.Get("board")
		queryString := fmt.Sprintf("UPDATE Running SET `%s`=-`%s`, `w-devil`=%s WHERE RmNo=%s", preRole, preRole, board, room)
		_, err = handle.Exec(queryString)
		if err == nil {
			fmt.Fprintln(w, "success")
		} else {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}

	case "g-hunter":         //   猎人操作
		board := post.Get("board")

		var death1,death2,death3 string
		err = handle.QueryRow("SELECT death1, death2, death3 FROM Running WHERE RmNo=?", room).Scan(&death1,&death2,&death3)
		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			return
		}

		if (death1 == self || death2 == self || death3 == self) && checkDevil(board, room){
			fmt.Fprintln(w, "devil")
		}else{
			queryString := fmt.Sprintf("UPDATE Running SET `g-hunter`=%s WHERE RmNo=%s", board, room)
			_, err = handle.Exec(queryString)
			if err == nil {
				queryString = fmt.Sprintf("UPDATE player SET survival = 0 WHERE No = %s", board)
				_, err = handle.Exec(queryString)
				if err == nil {
					fmt.Fprintln(w, "success")
				}else {
					http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
				}
			} else {
				http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			}
		}

	case "w-king":         //    狼王操作
		board := post.Get("board")
		queryString := fmt.Sprintf("UPDATE Running SET `w-king`=%s WHERE RmNo=%s", board, room)
		_, err = handle.Exec(queryString)
		if err == nil {
			queryString = fmt.Sprintf("UPDATE player SET survival = 0 WHERE No = %s", board)
			_, err = handle.Exec(queryString)
			if err == nil {
				fmt.Fprintln(w, "success")
			}else {
				http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			}
		} else {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}

	case "g-knight":         //    骑士操作

		board := post.Get("board")
		
		var rolelist []string
		JSONdata := r.URL.Query().Get("roleList")
		err := json.Unmarshal([]byte(JSONdata), &rolelist)
		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			return
		}
		
		var roleIndex int
		
		err = handle.QueryRow("SELECT Role FROM Player WHERE RmNo=? AND No=?", room, board).Scan(&roleIndex)

		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			return
		}

		if rolelist[roleIndex-1][0] != 'w'{
			fmt.Fprintln(w, "not-wolf")
			_, err = handle.Exec("UPDATE player SET survival=0 WHERE RmNo = ? AND username = ?" , room, self)
			if err != nil {
				http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			}
		}else{
			fmt.Fprintln(w, "success")
			_, err = handle.Exec("UPDATE player SET survival = 0 WHERE RmNo = ? AND No = ?", room, board)
			if err != nil {
				http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
			}
		}
		
		_, err = handle.Exec("UPDATE Running SET `g-knight`=? WHERE RmNo=?", board, room)
		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}

	case "self-boom":         //    自爆角色操作

		_, err = handle.Exec("UPDATE player SET survival=0 WHERE RmNo = ? AND username = ?", room, self)
		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}

		json.NewEncoder(w).Encode("success")
	
	case "skip":

		board := post.Get("board")


		ExecThing := fmt.Sprintf("UPDATE Running SET `%s` = %s WHERE RmNo = %s", post.Get("role"), board, room)
		_, err =handle.Exec(ExecThing)

		if err != nil {
			http.Error(w, "error:" + err.Error(), http.StatusInternalServerError)
		}
		
	default:
		http.Error(w, "Invalid role", http.StatusBadRequest)
	}
}

func checkDevilKnight(id string, room string, self string) string {          //  检查要毒杀或者查验的对象是否是恶灵骑士，如果是，则返回查验者的id，否则返回原来的id
	handle, err := core.Connection()
	if err != nil {
		fmt.Println("Connection failed: " + err.Error())
		return id
	}
	defer handle.Close()
	var roles string
	var ms string
	err = handle.QueryRow("SELECT Role FROM Game WHERE RmNo=?", room).Scan(&roles)
	if err != nil {
		fmt.Println("Error fetching game info: " + err.Error())
		return id
	}
	roleList := strings.Split(roles, ";")
	err = handle.QueryRow("SELECT Role FROM Player WHERE RmNo=? AND No=?", room, id).Scan(&ms)
	if err != nil {
		fmt.Println("Error fetching role: " + err.Error())
		return id
	}
	mIndex, _ := strconv.Atoi(ms)
	if mIndex >= len(roleList) {
		return id
	} else if roleList[mIndex-1] == "w-knight" {
		var is_used int
		err = handle.QueryRow("SELECT `w-knight` FROM Running WHERE RmNo=?", room).Scan(&is_used)
		if err != nil {
			fmt.Println("Error fetching w-knight info: " + err.Error())
			return id
		}
		if is_used != 0 {
			return id
		}else{
			_, err = handle.Exec("UPDATE Running SET `w-knight` = 1 WHERE RmNo=?", room)
			if err != nil {
				fmt.Println("Error updating w-knight info: " + err.Error())
				return id
			}

			var selfid int
			err = handle.QueryRow("SELECT No FROM Player WHERE RmNo=? AND username=?", room, self).Scan(&selfid)
			if err != nil {
				fmt.Println("Error fetching self id: " + err.Error())
				return id
			}

			return strconv.Itoa(selfid)
		}
	}
	return id
}

func checkDevil(id string, room string) bool {          //  检查要袭击的对象是否是恶魔，如果是，则返回true，否则返回false 恶魔无法在夜间死亡
	handle, err := core.Connection()
	if err != nil {
		fmt.Println("Connection failed: " + err.Error())
		return false
	}
	defer handle.Close()
	var roles string
	var ms string
	err = handle.QueryRow("SELECT Role FROM Game WHERE RmNo=?", room).Scan(&roles)
	if err != nil {
		fmt.Println("Error fetching game info: " + err.Error())
		return false
	}
	roleList := strings.Split(roles, ";")
	err = handle.QueryRow("SELECT Role FROM Player WHERE RmNo=? AND No=?", room, id).Scan(&ms)
	if err != nil {
		fmt.Println("Error fetching role: " + err.Error())
		return false
	}
	mIndex, _ := strconv.Atoi(ms)
	if mIndex >= len(roleList) {
		return false
	} else if roleList[mIndex-1] == "w-devil" {
		return true
	}
	return false
}
